package com.hns.tool.export.excel.excelTemplate;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hns.can.common.domain.Dataset;
import com.hns.can.common.domain.Field;
import com.hns.can.common.domain.Record;
import com.hns.tool.pub.PubUtil;

/**
 * 读取excel文件，并按指定的格式解析、保存数据到dataset
 * @author:Fisher
 * @email:zhuangcaijin@126.com
 * @version Revision 2.0.0
 */
public class Excel2Dataset {

	static final Logger logger = LoggerFactory.getLogger(Excel2Dataset.class);

	/**
	 * 解析excel文件内容，读取数据到dataset中 默认读取第一sheet的数据，第一行为表头，第二行开始为数据行
	 * @param excelFile 待解析的excel
	 * @param template 数据集,表明每列数据的变量名和数据类型
	 * @return 解析后的数据集
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static Dataset parse(String excelFile, Dataset template) {
		return parse(excelFile, 1, 1, template);
	}

	/**
	 * 解析excel文件内容，读取数据到dataset中
	 * @param excelFile 待解析的excel
	 * @param page 想要解析的sheet页，从1开始，1表示第一页
	 * @param titleRow 表头行，指明第几行为表头，以下行为数据行
	 * @param template 数据集,表明每列数据的变量名和数据类型
	 * @return 解析后的数据集
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	//TODO
	public static Dataset parse(String excelFile, int page, int titleRow, Dataset template) {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(excelFile);
			return parseStream(fis, page, titleRow, template);
		} catch (FileNotFoundException e) {
			logger.error(e.getMessage(), e.getCause());
			throw new RuntimeException(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage(), e.getCause());
			throw new RuntimeException(e.getMessage());
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					logger.error(e.getMessage(), e.getCause());
				}
			}
		}
	}

	/**
	 * 解析excel文件内容，读取数据到dataset中 默认读取第一sheet的数据，第一行为表头，第二行开始为数据行
	 * @param excelFileStream 待解析的excel输入流
	 * @param template 数据集,表明每列数据的变量名和数据类型
	 * @return 解析后的数据集
	 * @throws IOException
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static Dataset parseStream(InputStream excelFileStream, Dataset template) throws IOException {
		return parseStream(excelFileStream, 1, 1, template);
	}
	
	/**
	 * 生成用于导出excel工作簿
	 * @param excelFileStream 待解析的excel
	 * @return excel工作簿
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static HSSFWorkbook getWorkBook(InputStream excelFileStream){
		HSSFWorkbook book = null;
		try {
			book = new HSSFWorkbook(excelFileStream);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return book;
	}

	/**
	 * 获取excel工作簿sheet数
	 * @param book excel工作簿
	 * @return excel工作簿sheet数
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static int getSheetCount(HSSFWorkbook book) {
		// 读取excel第page页
		try {
			return book.getNumberOfSheets();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 得到sheet的名称
	 * @param bk excel工作簿
	 * @param page sheet序号
	 * @return sheet的名称
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static String getSheetName(HSSFWorkbook bk, int page) {
		return bk.getSheetName(page);
	}

	/**
	 * 解析excel文件内容，读取数据到dataset中
	 * @param excelFileStream 待解析的excel
	 * @param page 想要解析的sheet页，从1开始，1表示第一页
	 * @param titleRow 表头行，指明第几行为表头，以下行为数据行
	 * @param template 数据集,表明每列数据的变量名和数据类型
	 * @return 解析后的数据集
	 * @throws IOException
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	//TODO
	public static Dataset parseStream(InputStream excelFileStream, int page, int titleRow, Dataset template) throws IOException {
		page = page - 1;
		if (page < 0) {
			page = 0;
		}
		titleRow = titleRow - 1;
		if (titleRow < 0) {
			titleRow = 0;
		}
		Dataset result = template.copy(false);
		List<Field> fields = template.getFieldList();

		// excel的column 与 dataset的field 之间的对应关系
		Map<Integer, Field> columnMatchs = new HashMap<Integer, Field>();

		// 读取excel第page页
		HSSFWorkbook book = new HSSFWorkbook(excelFileStream);
		HSSFSheet sheet = book.getSheetAt(page);

		// 如果page页不存在，取得活动页，否则取第一页
		if (sheet == null || sheet.getPhysicalNumberOfRows() == 0) {
			sheet = book.getSheetAt(book.getActiveSheetIndex());
			if (sheet == null || sheet.getPhysicalNumberOfRows() == 0) {
				sheet = book.getSheetAt(0);
			}
		}

		// 读取excel标题行，匹配到dataset中field的label上
		Row row = sheet.getRow(titleRow);
		if (row == null) {
			throw new RuntimeException("no title row");
		}
		int cells = row.getPhysicalNumberOfCells();
		for (int i = 0; i < cells; i++) {
			Cell cell = row.getCell(i);
			if (cell != null) {
				String label = cell.getStringCellValue();
				Field field = getField(fields, label);
				if (field != null) {
					columnMatchs.put(i, field);
				}
			}
		}

		// 读取title行以下数据行
		int rows = sheet.getPhysicalNumberOfRows();
		for (int r = titleRow + 1; r < rows; r++) {
			row = sheet.getRow(r);
			if (row != null) {
				Record record = new Record();
				// cells = row.getPhysicalNumberOfCells();
				// cells = row.getLastCellNum();
				for (int i = 0; i < cells; i++) {
					try {
						readCellValue(row.getCell(i), columnMatchs, record);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				result.addRecord(record);
			}
		}

		return result;
	}

	/**
	 * 解析excel工作簿中的内容，读取数据到dataset中
	 * @param book 待解析的excel工作簿对象
	 * @param page 想要解析的sheet页，从1开始，1表示第一页
	 * @param titleRow 表头行，指明第几行为表头，以下行为数据行
	 * @param template 数据集,表明每列数据的变量名和数据类型
	 * @return 解析后的数据集
	 * @throws IOException
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public static Dataset parseStream(HSSFWorkbook book, int page, int titleRow, Dataset template) throws IOException {
		page = page - 1;
		if (page < 0) {
			page = 0;
		}
		titleRow = titleRow - 1;
		if (titleRow < 0) {
			titleRow = 0;
		}
		Dataset result = template.copy(false);
		List<Field> fields = template.getFieldList();

		// excel的column 与 dataset的field 之间的对应关系
		Map<Integer, Field> columnMatchs = new HashMap<Integer, Field>();

		// 读取excel第page页
		HSSFSheet sheet = book.getSheetAt(page);

		// 如果page页不存在，取得活动页，否则取第一页
		if (sheet == null || sheet.getPhysicalNumberOfRows() == 0) {
			sheet = book.getSheetAt(book.getActiveSheetIndex());
			if (sheet == null || sheet.getPhysicalNumberOfRows() == 0) {
				sheet = book.getSheetAt(0);
			}
		}

		// 读取excel标题行，匹配到dataset中field的label上
		Row row = sheet.getRow(titleRow);
		if (row == null) {
			throw new RuntimeException("no title row");
		}
		int cells = row.getPhysicalNumberOfCells();
		for (int i = 0; i < cells; i++) {
			Cell cell = row.getCell(i);
			if (cell != null) {
				String label = cell.getStringCellValue();
				Field field = getField(fields, label);
				if (field != null) {
					columnMatchs.put(i, field);
				}
			}
		}

		// 读取title行以下数据行
		int rows = sheet.getPhysicalNumberOfRows();
		for (int r = titleRow + 1; r < rows; r++) {
			row = sheet.getRow(r);
			if (row != null) {
				Record record = new Record();
				// cells = row.getPhysicalNumberOfCells();
				// cells = row.getLastCellNum();
				for (int i = 0; i < cells; i++) {
					readCellValue(row.getCell(i), columnMatchs, record);
				}
				result.addRecord(record);
			}
		}

		return result;
	}

	/**
	 * 获取指定字段名对应的字段
	 * @param fields 字段list
	 * @param fieldLabel 字段名
	 * @return 字段对象
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	//TODO
	private static Field getField(List<Field> fields, String fieldLabel) {
		for (Field field : fields) {
			if (field.getLabel().equals(fieldLabel)) {
				return field;
			}
		}
		return null;
	}

	/**
	 * 填充一行记录中指定单元格内容
	 * @param cell 单元格
	 * @param columnMatchs 字段map <字段序号, 字段对象>
	 * @param record 记录行
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	//TODO
	private static void readCellValue(Cell cell, Map<Integer, Field> columnMatchs, Record record) {
		if (cell != null) {
			Field field = columnMatchs.get(cell.getColumnIndex());
			if (field != null) {
				String dataType = field.getDataType();
				String strValue;
				Object value = null;

				// string ,boolean ,short ,integer ,long ,float ,double
				// ,bigdecimal ,date ,timestamp
				if (Field.DATA_TYPE_STRING.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = String.valueOf(cell.getNumericCellValue());
						break;
					default:
						value = cell.getStringCellValue();
					}
				}
				if (Field.DATA_TYPE_BOOLEAN.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_BOOLEAN:
						value = cell.getBooleanCellValue();
						break;
					case Cell.CELL_TYPE_NUMERIC:
						value = cell.getNumericCellValue() >= 1;
						break;
					default:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = "1".equals(strValue.trim());
						} else {
							value = false;
						}
					}
				}
				if (Field.DATA_TYPE_SHORT.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = Double.valueOf(cell.getNumericCellValue()).shortValue();
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = Short.valueOf(strValue.trim());
						} else {
							value = Short.valueOf("0");
						}
					}
				}
				if (Field.DATA_TYPE_INTEGER.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = Double.valueOf(cell.getNumericCellValue()).intValue();
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = Integer.valueOf(strValue.trim());
						} else {
							value = null;
						}
					}
				}
				if (Field.DATA_TYPE_LONG.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = Double.valueOf(cell.getNumericCellValue()).longValue();
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = Long.valueOf(strValue.trim());
						} else {
							value = Long.valueOf("0");
						}
					}
				}
				if (Field.DATA_TYPE_FLOAT.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = Double.valueOf(cell.getNumericCellValue()).floatValue();
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = Float.valueOf(strValue.trim());
						} else {
							value = Float.valueOf("0");
						}
					}
				}
				if (Field.DATA_TYPE_DOUBLE.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = cell.getNumericCellValue();
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							value = Double.valueOf(strValue.trim());
						} else {
							value = Double.valueOf("0");
						}
					}
				}
				if (Field.DATA_TYPE_BIGDECIMAL.equals(dataType)) {
					switch (cell.getCellType()) {
					case Cell.CELL_TYPE_NUMERIC:
						value = BigDecimal.valueOf(cell.getNumericCellValue());
						break;
					case Cell.CELL_TYPE_BOOLEAN:
					case Cell.CELL_TYPE_STRING:
						strValue = cell.getStringCellValue();
						if (!PubUtil.isEmpty(strValue)) {
							//如果金额带有，则去除 20140303yulj
							strValue = strValue.replaceAll(",", "");
							value = new BigDecimal(strValue.trim());
						} else {
							value = BigDecimal.valueOf(0);
						}
					}
				}
				record.setValue(field.getName(), value);
			}
		}
	}
}
